package com.bert.generator.base.db;

import cn.hutool.core.util.StrUtil;
import com.bert.generator.base.GeneratorConfig;
import org.springframework.util.CollectionUtils;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * 数据库解析工具类
 */
public class ParseDBUtil {

    private final GeneratorConfig generatorConfig;

    public ParseDBUtil(GeneratorConfig generatorConfig) {
        this.generatorConfig = generatorConfig;
    }

    /**
     * 根据配置，解析数据库信息
     *
     * @return
     */
    public List<DBInfo> parseDBs() {
        List<DBInfo> dbInfos = new ArrayList<>(generatorConfig.getDbNames().size());
        for (String dbName : generatorConfig.getDbNames()) {
            dbInfos.add(parseDB(generatorConfig.getDbUserName(), generatorConfig.getDbPwd(), generatorConfig.getDbHost(), generatorConfig.getDbPort(), dbName));
        }
        return dbInfos;
    }

    /**
     * 解析数据库信息
     *
     * @param username
     * @param password
     * @param host
     * @param port
     * @param dbName
     * @return
     */
    private DBInfo parseDB(String username, String password, String host, int port, String dbName) {
        try {
            Connection connection = createConnection(username, password, host, port, dbName);
            List<TableInfo> tableInfos = tableInfos(dbName, connection);
            connection.close();
            return new DBInfo(dbName, tableInfos);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return null;
    }

    /**
     * 获取所有表信息集合
     *
     * @param connection
     * @return
     */
    private List<TableInfo> tableInfos(String dbName, Connection connection) throws SQLException {
        //表名
        List<TableInfo> tableInfos = new ArrayList<>();
        ResultSet resultSet = connection.getMetaData().getTables(null, null, "%", new String[]{"TABLE"});
        while (resultSet.next()) {

            String tableName = resultSet.getString("TABLE_NAME");
            //排除的表不需要添加进tableInfos
            if (generatorConfig.getExcludeTableNames().contains(tableName)) {
                continue;
            }
            String comment = resultSet.getString("REMARKS");
            if (!CollectionUtils.isEmpty(generatorConfig.getOnlyNeedTableNames())) {
                if (generatorConfig.getOnlyNeedTableNames().contains(tableName)) {
                    tableInfos.add(getTableInfo(dbName, tableName, comment, connection));
                }
                continue;
            }
            tableInfos.add(getTableInfo(dbName, tableName, comment, connection));
        }
        return tableInfos;
    }

    /**
     * 组装表信息
     *
     * @param dbName
     * @param tableName
     * @param comment
     * @param connection
     * @return
     * @throws SQLException
     */
    private TableInfo getTableInfo(String dbName, String tableName, String comment, Connection connection) throws SQLException {
        TableInfo tableInfo = new TableInfo();
        tableInfo.setOwnerDbName(dbName);
        tableInfo.setTableName(tableName);
        tableInfo.setComment(comment);
        tableInfo.setModuleName(generatorConfig.matchModuleName(tableName));
        tableInfo.setPackageName(generatorConfig.matchPackageName(tableName));
        tableInfo.setPrefix(generatorConfig.getTablePrefix(tableName));
        tableInfo.setColumnInfoList(columnInfos(tableInfo, connection));
        return tableInfo;
    }

    /**
     * 获取表的所有列信息
     *
     * @param tableInfo
     * @param connection
     * @return
     */
    private static List<ColumnInfo> columnInfos(TableInfo tableInfo, Connection connection) throws SQLException {
        List<ColumnInfo> columnInfoList = new ArrayList<>();
        ResultSet resultSet = connection.getMetaData().getColumns(tableInfo.getOwnerDbName(), "", tableInfo.getTableName(), "%");
        while (resultSet.next()) {
            ColumnInfo columnInfo = new ColumnInfo();
            columnInfo.setColumnName(resultSet.getString("COLUMN_NAME"));
            columnInfo.setComment(resultSet.getString("REMARKS"));
            columnInfo.setJdbcType(JdbcType.valueOf(resultSet.getString("TYPE_NAME")));
            columnInfo.setJavaType(JdbcType.getJavaType(columnInfo.getJdbcType()).getSimpleName());
            columnInfo.setFieldName(StrUtil.toCamelCase(columnInfo.getColumnName()));
            columnInfoList.add(columnInfo);
        }
        return columnInfoList;
    }

    /**
     * 创建数据库连接
     *
     * @param username
     * @param password
     * @param host
     * @param port
     * @param dbName
     * @return
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    private static Connection createConnection(String username, String password, String host, int port, String dbName) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Properties properties = new Properties();
        properties.put("user", username);
        properties.put("password", password);
        properties.setProperty("remarks", "true");
        properties.setProperty("useInformationSchema", "true");
        String url = "jdbc:mysql://" + host + ":" + port + "/" + dbName + "?serverTimezone=GMT&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&nullCatalogMeansCurrent=true";
        return DriverManager.getConnection(url, properties);
    }


}
